package com.atguigu.tingshu.album.service.impl;

import com.atguigu.tingshu.album.config.VodConstantProperties;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackStatMapper;
import com.atguigu.tingshu.album.service.TrackInfoService;
import com.atguigu.tingshu.album.service.VodService;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.common.util.UploadFileUtil;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.album.TrackStat;
import com.atguigu.tingshu.model.user.UserPaidTrack;
import com.atguigu.tingshu.query.album.TrackInfoQuery;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.album.*;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qcloud.vod.VodUploadClient;
import com.qcloud.vod.model.VodUploadRequest;
import com.qcloud.vod.model.VodUploadResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.util.Asserts;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class TrackInfoServiceImpl extends ServiceImpl<TrackInfoMapper, TrackInfo> implements TrackInfoService {
    @Autowired
    private TrackInfoMapper trackInfoMapper;
    @Autowired
    private VodConstantProperties vodConstantProperties;
    @Autowired
    private AlbumInfoMapper albumInfoMapper;
    @Autowired
    private VodService vodService;
    @Autowired
    private TrackStatMapper trackStatMapper;
    @Autowired
    private UserInfoFeignClient userInfoFeignClient;

    /**
     * 上传声音文件
     *
     * @param file
     * @return
     */
    @Override
    public Map<String, Object> uploadTrack(MultipartFile file) {//初始化一个上传客户端对象
        //使用云 API 密钥初始化 VodUploadClient 实例。
        VodUploadClient client = new VodUploadClient(vodConstantProperties.getSecretId(), vodConstantProperties.getSecretKey());
        //  声音上传临时目录：
        String tempPath = UploadFileUtil.uploadTempPath(vodConstantProperties.getTempPath(), file);
        //构造上传请求对象
        //设置媒体本地上传路径。
        VodUploadRequest request = new VodUploadRequest();
        request.setMediaFilePath(tempPath);
        //调用上传方法，传入接入点地域及上传请求。
        try {
            VodUploadResponse response = client.upload(vodConstantProperties.getRegion(), request);
            log.info("Upload FileId = {}", response.getFileId());
            HashMap<String, Object> map = new HashMap<>();
            map.put("mediaFileId", response.getFileId());
            map.put("mediaUrl", response.getMediaUrl());
            return map;
        } catch (Exception e) {
            // 业务方进行异常处理
            log.error("Upload Err", e);
        }
        return new HashMap<>();
    }

    /**
     * 保存声音信息
     *
     * @param userId
     * @param trackInfoVo
     */
    @Override
    public void saveTrackInfo(long userId, TrackInfoVo trackInfoVo) {
        //	track_info
        TrackInfo trackInfo = new TrackInfo();
        //	属性拷贝
        BeanUtils.copyProperties(trackInfoVo, trackInfo);
        //	用户Id
        trackInfo.setUserId(userId);
        //	order_num 声音的序号
        //	根据专辑Id获取到专辑对象
        AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfoVo.getAlbumId());
        trackInfo.setOrderNum(albumInfo.getIncludeTrackCount() + 1);
        //	赋值流媒体相关字段数据 media_duration media_file_id media_size media_type; 可以调用云点播的api获取！
        TrackMediaInfoVo mediaInfo = vodService.getMediaInfo(trackInfoVo.getMediaFileId());
        trackInfo.setMediaSize(mediaInfo.getSize());
        trackInfo.setMediaDuration(mediaInfo.getDuration());
        trackInfo.setMediaUrl(mediaInfo.getMediaUrl());
        trackInfo.setMediaType(mediaInfo.getType());
        //	保存声音
        trackInfoMapper.insert(trackInfo);
        // 播放量
        this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_PLAY);
        // 收藏量
        this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_COLLECT);
        // 点赞量
        this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_PRAISE);
        // 评论数
        this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_COMMENT);

        //  更新专辑对应的声音总数;
        albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() + 1);
        this.albumInfoMapper.updateById(albumInfo);
    }

    /**
     * 分页查询用户声音
     *
     * @param pageNum
     * @param pageSize
     * @param trackInfoQuery
     * @return
     */
    @Override
    public IPage<TrackListVo> findUserTrackPage(Long pageNum, Long pageSize, TrackInfoQuery trackInfoQuery) {
        Page<TrackListVo> page = new Page<>(pageNum, pageSize);
        return trackInfoMapper.selectUserTrackPage(page, trackInfoQuery);
    }

    /**
     * 删除声音
     *
     * @param trackId
     */
    @Override
    public void removeTrackInfo(Long trackId) {
        // 获取声音对象数据
        TrackInfo trackInfo = this.getById(trackId);
        // 删除
        this.removeById(trackId);
        //更新专辑声音总数
        AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfo.getAlbumId());
        Integer preIncludeTrackCount = albumInfo.getIncludeTrackCount() - 1;
        albumInfo.setIncludeTrackCount(preIncludeTrackCount);
        albumInfoMapper.updateById(albumInfo);
        //删除统计数据
        trackStatMapper.delete(new LambdaQueryWrapper<TrackStat>().eq(TrackStat::getTrackId, trackId));
        //  序号重新更新
        trackStatMapper.updateOrderNum(trackInfo.getAlbumId(), trackInfo.getOrderNum());
        //删除声音媒体
        vodService.removeTrack(trackInfo.getMediaFileId());
    }

    /**
     * 保存统计
     *
     * @param id
     * @param trackStatCollect
     */
    private void saveTrackStat(Long id, String trackStatCollect) {
        //  创建声音统计对象
        TrackStat trackStat = new TrackStat();
        //  赋值：
        trackStat.setTrackId(id);
        trackStat.setStatType(trackStatCollect);
        trackStat.setStatNum(new Random().nextInt(10000));

        trackStatMapper.insert(trackStat);
    }

    /**
     * 修改声音
     *
     * @param trackId
     * @param trackInfoVo
     */
    @Override
    public void updateTrackInfo(Long trackId, TrackInfoVo trackInfoVo) {
        //	获取到声音对象
        TrackInfo trackInfo = this.getById(trackId);
        //    获取传递的fileId
        String mediaFileId = trackInfo.getMediaFileId();
        //	进行属性拷贝
        BeanUtils.copyProperties(trackInfoVo, trackInfo);
        //	获取声音信息 页面传递的fileId 与 数据库的 fileId 不相等就修改
        if (!trackInfoVo.getMediaFileId().equals(mediaFileId)) {
            //获取传递 trackInfoVo中 音频id 的信息
            TrackMediaInfoVo mediaInfo = vodService.getMediaInfo(trackInfoVo.getMediaFileId());
            //	判断结果对象不为空.
            if (null == mediaInfo) {
                //	抛出异常 ResultCodeEnum.VOD_FILE_ID_ERROR
                throw new GuiguException(ResultCodeEnum.VOD_FILE_ID_ERROR);
            }
            //赋值声音信息
            trackInfo.setMediaSize(mediaInfo.getSize());
            trackInfo.setMediaDuration(mediaInfo.getDuration());
            trackInfo.setMediaUrl(mediaInfo.getMediaUrl());
            trackInfo.setMediaType(mediaInfo.getType());
            // 删除云点播声音
            vodService.removeTrack(trackInfoVo.getMediaFileId());
        }
        //	修改数据
        this.updateById(trackInfo);
    }

    /**
     * 获取声音列表
     *
     * @param albumTrackListVoPage
     * @param albumId
     * @param userId
     * @return
     */
    @Override
    public IPage<AlbumTrackListVo> findAlbumTrackPage(Page<AlbumTrackListVo> albumTrackListVoPage, Long albumId, Long userId) {
        //  先获取当前专辑对应声音列表！
        IPage<AlbumTrackListVo> trackInfoList = trackInfoMapper.findAlbumTrackPage(albumTrackListVoPage, albumId);
        Assert.notNull(trackInfoList.getRecords(), "声音列表为空");
        //获取专辑信息 获取免费级数   判断用户是否需要付费：0101-免费 0102-vip免费 0103-付费
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        Assert.notNull(albumInfo, "专辑信息不存在");
        //  说明未登录！需要设置当前试听的声音免费 isShowPaidMark = false，其他声音收费 isShowPaidMark = true;
        if (null == userId) {
            //  先找到免费试听的集数;
            Integer tracksForFree = albumInfo.getTracksForFree();
            //  主要设置是否需要付费字段 isShowPaidMark;   //  select * from track_info where order_num > 5 and album_id = 1429;
            trackInfoList.getRecords().stream().filter(trackInfo -> trackInfo.getOrderNum() > tracksForFree).forEach(trackInfo -> trackInfo.setIsShowPaidMark(true));
            return trackInfoList;
        } else { //登录 是否vip 专辑是否vip免费 是否付费专辑  vip是否过期  非vip 走付费专辑流程
            //获取用户信息 结果集
            Result<UserInfoVo> userInfoVo = this.userInfoFeignClient.getUserInfoVo(userId);
            Assert.notNull(userInfoVo.getData(), "用户信息不存在");
            //获取结果集中的数据
            UserInfoVo userInfoVoData = userInfoVo.getData();
            //设置一个字段 默认不需要付费 通过不同条件判断 修改为需要付费
            boolean isNeedPaidMark = false;
            //判断专辑付费类别与用户类别 // 0102 vip免费
            if (SystemConstant.ALBUM_PAY_TYPE_VIPFREE.equals(albumInfo.getPayType())) {
                //当前专辑是vip免费
                // 判断用户是vip但vip过期 或非vip 设置为付费
                if ((1 == userInfoVoData.getIsVip() && userInfoVoData.getVipExpireTime().before(new Date())) || 0 == userInfoVoData.getIsVip()) {
                    isNeedPaidMark = true;
                }
            } else if (SystemConstant.ALBUM_PAY_TYPE_REQUIRE.equals(albumInfo.getPayType())) {
                //当前专辑是付费类型 无论是否vip都需要付费
                isNeedPaidMark = true;
            }
            //  统一处理 付费结果
            //  除去用户购买的专辑 或购买的声音之外 需要付费
            //  {user_paid_album 用户购买专辑表，user_paid_track 用户购买声音表}
            if (isNeedPaidMark) {
                //获取声音列表下 需要付费的声音信息
                List<AlbumTrackListVo> trackNeedPaidList = trackInfoList.getRecords().stream().filter(trackInfo -> trackInfo.getOrderNum() > albumInfo.getTracksForFree()).collect(Collectors.toList());
                //获取需要付费的声音信息 的声音id list
                List<Long> trackNeedPaidIdList = trackNeedPaidList.stream().map(AlbumTrackListVo::getTrackId).collect(Collectors.toList());
                // 远程调用 用户模块 判断用户是否购买专辑 或 是否购买该专辑下的声音
                Result<Map<Long, Integer>> mapResult = userInfoFeignClient.userIsPaidTrack(albumId, trackNeedPaidIdList);
                Assert.notNull(mapResult, "用户购买专辑信息不存在");
                Map<Long, Integer> mapResultData = mapResult.getData();
                Assert.notNull(mapResultData, "用户购买专辑信息不存在");

                for (AlbumTrackListVo albumTrackListVo : trackNeedPaidList) {
                    albumTrackListVo.setIsShowPaidMark(mapResultData.get(albumTrackListVo.getTrackId()) == 1 ? false : true);
                }
            }
        }
        return trackInfoList;
    }

    /**
     * 更新声音信息表播放量、专辑信息表播放量
     *
     * @param trackStatMqVo1
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateTrackStat(TrackStatMqVo trackStatMqVo1) {

        this.trackInfoMapper.updateTrackStat(trackStatMqVo1.getTrackId(), trackStatMqVo1.getCount(), trackStatMqVo1.getStatType());

        if (SystemConstant.TRACK_STAT_PLAY.equals(trackStatMqVo1.getStatType())) {
            this.albumInfoMapper.updateTrackStat(trackStatMqVo1.getAlbumId(), SystemConstant.ALBUM_STAT_PLAY, trackStatMqVo1.getCount());
        }
    }

    /**
     * 获取用户购买声音信息
     *
     * @param userId
     * @param trackId
     * @return 1.从当前声音Id 开始，往后有多少集需要付款！
     * a. select * from track_info where id = 48241findUserPaidTrackList;  # album_id=1429 order_num = 6;
     * b. select * from track_info where album_id = 1429 and order_num > 6; (获取所有要购买的声音列表)
     * c. select * from user_paid_track where user_id = 28 and album_id = 1429; 除去用户已购买过的声音Id;
     * 2.b,c 去重复! 获取到最终的总条数！
     * 在根据规则，进行设置购买多少集！（每10个一个阶梯，不够10，买所有！）
     */
    @Override
    public List<Map<String, Object>> findUserTrackPaidList(Long trackId) {
        TrackInfo trackInfo = trackInfoMapper.selectById(trackId);//a. select * from track_info where id = 48241;  # album_id=1429 order_num = 6;
        //b. select * from track_info where album_id = 1429 and order_num > 6; (获取所有要购买的声音列表)
        LambdaQueryWrapper<TrackInfo> wrapper = new LambdaQueryWrapper<TrackInfo>().eq(TrackInfo::getAlbumId, trackInfo.getAlbumId()).gt(TrackInfo::getOrderNum, trackInfo.getOrderNum());
        List<TrackInfo> trackInfos = trackInfoMapper.selectList(wrapper);
        //转换为id list 表
        List<Long> trackIdAllList = trackInfos.stream().map(TrackInfo::getId).collect(Collectors.toList());
        //远程调用User服务，获取用户已购买过的声音Id
        // c. select * from user_paid_track where user_id = 28 and album_id = 1429; 除去用户已购买过的声音Id;
        Result<List<Long>> trackIdListResult = userInfoFeignClient.findUserPaidTrackList(trackInfo.getAlbumId());
        Assert.notNull(trackIdListResult, "用户购买声音信息不存在");
        List<Long> resultData = trackIdListResult.getData();
        //b,c 去重复! 获取到最终的总条数！
        //创建未支付的trackId List
        List<Long> trackIdNoPaidList = new ArrayList<>();
        if (CollectionUtils.isEmpty(resultData)) {
            trackIdNoPaidList = trackIdAllList;
        } else {
            trackIdNoPaidList = trackIdAllList.stream().filter(result -> !resultData.contains(result)).collect(Collectors.toList());
        }
        //获取专辑信息，返回专辑声音价格
        AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfo.getAlbumId());
        //创建返回结果集
        ArrayList<Map<String, Object>> list = new ArrayList<>();
        // 需要付款的集数有 19
        // 本集
        if (trackIdNoPaidList.size() >= 0) {
            HashMap<String, Object> map = new HashMap<>();
            map.put("name", "本集");
            map.put("price", albumInfo.getPrice());
            map.put("trackCount", 0);
            list.add(map);
        }
        //9 后九集
        if (trackIdNoPaidList.size() > 0 && trackIdNoPaidList.size() <= 10) {
            HashMap<String, Object> map = new HashMap<>();
            map.put("name", "后"+trackIdNoPaidList.size()+"集");
            map.put("price", albumInfo.getPrice().multiply(new BigDecimal(trackIdNoPaidList.size())));
            map.put("trackCount", trackIdNoPaidList.size());
            list.add(map);
        }
        //19 后10集
        if (trackIdNoPaidList.size() > 10) {
            HashMap<String, Object> map = new HashMap<>();
            map.put("name", "后10集");
            map.put("price", albumInfo.getPrice().multiply(new BigDecimal("10")));
            map.put("trackCount", 10);
            list.add(map);
        }
        //19 后19集
        if (trackIdNoPaidList.size() > 10 && trackIdNoPaidList.size() <= 20) {
            HashMap<String, Object> map = new HashMap<>();
            map.put("name", "后"+trackIdNoPaidList.size()+"集");
            map.put("price", albumInfo.getPrice().multiply(new BigDecimal(trackIdNoPaidList.size())));
            map.put("trackCount", trackIdNoPaidList.size());
            list.add(map);
        }
        //29 后20集
        if (trackIdNoPaidList.size() > 20) {
            HashMap<String, Object> map = new HashMap<>();
            map.put("name", "后20集");
            map.put("price", albumInfo.getPrice().multiply(new BigDecimal("20")));
            map.put("trackCount", 20);
            list.add(map);
        }
        //29 后29集
        if (trackIdNoPaidList.size() > 20 && trackIdNoPaidList.size() <= 30) {
            HashMap<String, Object> map = new HashMap<>();
            map.put("name", "后"+trackIdNoPaidList.size()+"集");
            map.put("price", albumInfo.getPrice().multiply(new BigDecimal(trackIdNoPaidList.size())));
            map.put("trackCount", trackIdNoPaidList.size());
            list.add(map);
        }
        //39 后30集
        if (trackIdNoPaidList.size() > 30) {
            HashMap<String, Object> map = new HashMap<>();
            map.put("name", "后30集");
            map.put("price", albumInfo.getPrice().multiply(new BigDecimal("30")));
            map.put("trackCount", 30);
            list.add(map);
        }
        //39 后39集
        if (trackIdNoPaidList.size() > 30 && trackIdNoPaidList.size() <= 40) {
            HashMap<String, Object> map = new HashMap<>();
            map.put("name", "后"+trackIdNoPaidList.size()+"集");
            map.put("price", albumInfo.getPrice().multiply(new BigDecimal(trackIdNoPaidList.size())));
            map.put("trackCount", trackIdNoPaidList.size());
            list.add(map);
        }
        //59 后50集
        if (trackIdNoPaidList.size() > 50) {
            HashMap<String, Object> map = new HashMap<>();
            map.put("name", "后50集");
            map.put("price", albumInfo.getPrice().multiply(new BigDecimal("50")));
            map.put("trackCount", 50);
            list.add(map);
        }
        //59 后59集
        if (trackIdNoPaidList.size() > 40 && trackIdNoPaidList.size() <= 50) {
            HashMap<String, Object> map = new HashMap<>();
            map.put("name", "后"+trackIdNoPaidList.size()+"集");
            map.put("price", albumInfo.getPrice().multiply(new BigDecimal(trackIdNoPaidList.size())));
            map.put("trackCount", trackIdNoPaidList.size());
            list.add(map);
        }
        return list;
    }

    /**
     * 批量获取用户下单付费声音列表
     * @param trackId
     * @param trackCount
     * @return
     */
    @Override
    public List<TrackInfo> findPaidTrackInfoList(Long trackId, Integer trackCount) {
        //创建返回数据的集合
        List<TrackInfo> trackInfoList = new ArrayList<>();
        //根据声音id获取声音对象
        TrackInfo trackInfo = this.getById(trackId);
        //判断用户购买的声音 大于0继续向下执行
        if (trackCount>0) {
            //远程调用用户服务，获取用户购买的声音id集合
            Result<List<Long>> userPaidTrackList = userInfoFeignClient.findUserPaidTrackList(trackInfo.getAlbumId());
            Asserts.notNull(userPaidTrackList, "用户购买的声音id集合不存在");
            List<Long> userPaidTrackData = userPaidTrackList.getData();
            Asserts.notNull(userPaidTrackData, "用户购买的声音id集合不存在");
            //  查询数据; select * from track_info where album_id = 1429 and order_num > 6 and id not in (48244,48245,,48246) limit 10
            LambdaQueryWrapper<TrackInfo> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(TrackInfo::getAlbumId,trackInfo.getAlbumId());
            wrapper.gt(TrackInfo::getOrderNum,trackInfo.getOrderNum());
            //判断用户购买的声音集合 >0  大于0 添加not in
            if (userPaidTrackData.size()>0) {
                wrapper.notIn(TrackInfo::getId,userPaidTrackData);
            }
            //添加limit属性
            wrapper.last(" limit "+trackCount);
            //查询数据
            trackInfoList = trackInfoMapper.selectList(wrapper);

        }else{
            //长度=0 无购买记录 直接赋值 声音对象
            trackInfoList.add(trackInfo);
        }
        return trackInfoList;
    }
}
